#include "ParserList.h"

const string ParserList::regexInstructionAndArguments = "\\s*([a-zA-Z]+)\\s*(.*)";

const string ParserList::regexArgumentListMonth = "\\s*(month)\\s*";
const string ParserList::regexArgumentListWeek = "\\s*(week)\\s*";
const string ParserList::regexArgumentListDay = "\\s*(day)\\s*";
const string ParserList::regexArgumentListAll = "([\\s]*)";
const string ParserList::regexArgumentListSearchTerm = "\\s*(.+?)\\s*";

const string ParserList::regexInstructionList = "(list)";

ParserList::ParserList(ParserBase* _nextParser) : ParserBase(_nextParser) {
}

bool ParserList::tryParse(string userCommand, PARSED_COMMAND& parsedCommand){
	
	string instruction;
	string arguments;
	getInstructionAndArguments(userCommand, instruction, arguments);
	
	if (!checkInstruction(instruction)) {
		return false;
	}

	parseList(parsedCommand, arguments);

	return true;
}

bool ParserList::getInstructionAndArguments(const string& userCommand, 
										string& instruction, 
										string& arguments) {
	regex rgx(regexInstructionAndArguments);
	smatch matchResults;

	if (!regex_match(userCommand, matchResults, rgx)) {

		return false;
	}

	instruction = matchResults[INSTRUCTION_POS];
	if (matchResults.size() > ARGUMENTS_POS) {
		arguments = matchResults[ARGUMENTS_POS];
	}

	return true;
}

bool ParserList::checkInstruction(const string& instruction) {
	if (regex_match(instruction, regex(regexInstructionList,
									   tr1::regex_constants::icase))) {
		return true;
	}

	return false;
}

void ParserList::parseList(PARSED_COMMAND& parsedCommand,
				  const string& arguments) {
	smatch matchResults;

	CommandType commandType = categorizeListCommand(arguments, matchResults);

	switch (commandType) {
	case LIST_ALL:
		makeParsedCommandListAll(parsedCommand, matchResults);
		break;
	case LIST_DAY:
		makeParsedCommandListDay(parsedCommand, matchResults);
		break;
	case LIST_MONTH:
		makeParsedCommandListMonth(parsedCommand, matchResults);
		break;
	case LIST_WEEK:
		makeParsedCommandListWeek(parsedCommand, matchResults);
		break;
	case LIST_SEARCH_TERM:
		makeParsedCommandListSearchTerm(parsedCommand, matchResults);
		break;
	default:
		throw (range_error("Unexpected commandType for 'list' instruction"));
	}
}

ParserList::CommandType ParserList::categorizeListCommand(const string& arguments, 
												 smatch& matchingResults) {
	CommandType returnedCommandType;

	if (regex_match(arguments, matchingResults, regex(regexArgumentListAll))) {
		returnedCommandType = LIST_ALL;
	}else if (regex_match(arguments, matchingResults, regex(regexArgumentListMonth))) {
		returnedCommandType = LIST_MONTH;
	}else if (regex_match(arguments, matchingResults, regex(regexArgumentListWeek))) {
		returnedCommandType = LIST_WEEK;
	}else if (regex_match(arguments, matchingResults, regex(regexArgumentListDay))) {
		returnedCommandType = LIST_DAY;
	}else if (regex_match(arguments, matchingResults, regex(regexArgumentListSearchTerm))) {
		returnedCommandType = LIST_SEARCH_TERM;
	}else {
		returnedCommandType = INVALID;
	}

	return returnedCommandType;
}

void ParserList::makeParsedCommandListAll(PARSED_COMMAND& parsedCommand, 
											  smatch& matchingArguments) {
	parsedCommand.commandType = LIST_ALL;
}

void ParserList::makeParsedCommandListWeek(PARSED_COMMAND& parsedCommand, 
											  smatch& matchingArguments) {
	parsedCommand.commandType = LIST_WEEK;
}

void ParserList::makeParsedCommandListMonth(PARSED_COMMAND& parsedCommand, 
											  smatch& matchingArguments) {
	parsedCommand.commandType = LIST_MONTH;
}

void ParserList::makeParsedCommandListDay(PARSED_COMMAND& parsedCommand, 
											  smatch& matchingArguments) {
	parsedCommand.commandType = LIST_DAY;
}

void ParserList::makeParsedCommandListSearchTerm(PARSED_COMMAND& parsedCommand, 
											  smatch& matchingArguments) {
	parsedCommand.commandType = LIST_SEARCH_TERM;
	parsedCommand.listSearchTerm = matchingArguments[ARGUMENT_POS_LIST_SEARCH_TERM];
}
